package main

import (
	"fmt"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"sync"
	"time"
)

// ServiceStatus 跟踪服务状态
type ServiceStatus struct {
	IsRunning     bool
	FailureCount  int
	LastStartTime time.Time
	LastError     string
}

// 全局服务状态跟踪
var (
	serviceStatuses      = make(map[string]*ServiceStatus)
	serviceStatusesMutex sync.RWMutex
)

// IsProcessRunning 检查指定进程是否正在运行
func IsProcessRunning(processName string) (bool, error) {
	var cmd *exec.Cmd

	switch runtime.GOOS {
	case "windows":
		// Windows 使用 tasklist 命令
		cmd = exec.Command("tasklist", "/FI", fmt.Sprintf("IMAGENAME eq %s.exe", processName))
	case "linux", "darwin":
		// Linux/macOS 使用 pgrep 命令
		cmd = exec.Command("pgrep", "-f", processName)
	default:
		return false, fmt.Errorf("不支持的操作系统: %s", runtime.GOOS)
	}

	output, err := cmd.Output()
	if err != nil {
		// pgrep 在没有找到进程时会返回错误，这是正常的
		if runtime.GOOS != "windows" {
			return false, nil
		}
		return false, fmt.Errorf("执行进程检查命令失败: %v", err)
	}

	outputStr := string(output)

	switch runtime.GOOS {
	case "windows":
		// Windows: 检查输出中是否包含进程名
		return strings.Contains(outputStr, processName), nil
	default:
		// Linux/macOS: 如果有输出说明找到了进程
		return len(strings.TrimSpace(outputStr)) > 0, nil
	}
}

// StartService 启动服务
func StartService(service *ServiceConfig) error {
	// 检查可执行文件是否存在
	if _, err := os.Stat(service.Executable); os.IsNotExist(err) {
		return fmt.Errorf("可执行文件不存在: %s", service.Executable)
	}

	// 检查工作目录是否存在
	if service.WorkDir != "" {
		if _, err := os.Stat(service.WorkDir); os.IsNotExist(err) {
			return fmt.Errorf("工作目录不存在: %s", service.WorkDir)
		}
	}

	// 创建命令
	cmd := exec.Command(service.Executable, service.Args...)

	// 设置工作目录
	if service.WorkDir != "" {
		cmd.Dir = service.WorkDir
	}

	// 启动服务（后台运行）
	err := cmd.Start()
	if err != nil {
		return fmt.Errorf("启动服务失败: %v", err)
	}

	// 等待一小段时间确保服务启动
	time.Sleep(2 * time.Second)

	// 验证服务是否真的启动了
	isRunning, checkErr := IsProcessRunning(service.ProcessName)
	if checkErr != nil {
		return fmt.Errorf("验证服务启动状态失败: %v", checkErr)
	}

	if !isRunning {
		return fmt.Errorf("服务启动后未能检测到运行状态")
	}

	return nil
}

// CheckService 检查服务状态并在需要时启动
func CheckService(service *ServiceConfig) (bool, error) {
	// 检查服务是否正在运行
	isRunning, err := IsProcessRunning(service.ProcessName)
	if err != nil {
		return false, fmt.Errorf("检查进程状态失败: %v", err)
	}

	if isRunning {
		return true, nil
	}

	// 服务未运行，尝试启动
	fmt.Printf("服务 %s 未运行，尝试启动...\n", service.Name)

	err = StartService(service)
	if err != nil {
		return false, fmt.Errorf("启动服务失败: %v", err)
	}

	fmt.Printf("服务 %s 启动成功\n", service.Name)
	return true, nil
}

// GetServiceStatus 获取服务状态
func GetServiceStatus(serviceName string) *ServiceStatus {
	serviceStatusesMutex.RLock()
	defer serviceStatusesMutex.RUnlock()

	status, exists := serviceStatuses[serviceName]
	if !exists {
		return &ServiceStatus{
			IsRunning:     false,
			FailureCount:  0,
			LastStartTime: time.Time{},
			LastError:     "",
		}
	}
	return status
}

// UpdateServiceStatus 更新服务状态
func UpdateServiceStatus(serviceName string, isRunning bool, err error) {
	serviceStatusesMutex.Lock()
	defer serviceStatusesMutex.Unlock()

	status, exists := serviceStatuses[serviceName]
	if !exists {
		status = &ServiceStatus{}
		serviceStatuses[serviceName] = status
	}

	status.IsRunning = isRunning

	if err != nil {
		status.FailureCount++
		status.LastError = err.Error()
	} else if isRunning {
		// 服务正常运行，重置失败计数
		status.FailureCount = 0
		status.LastError = ""
		status.LastStartTime = time.Now()
	}
}

// sendServiceFailureEmail 发送服务失败邮件
func sendServiceFailureEmail(config *Config, service *ServiceConfig, status *ServiceStatus) {
	currentTime := time.Now().Format("2006-01-02 15:04:05")
	subject := fmt.Sprintf("[%s] 服务监控警告 - %s", currentTime, service.Name)

	body := fmt.Sprintf(`服务 %s 启动失败已达到最大重试次数

服务信息:
- 服务名称: %s
- 可执行文件: %s
- 工作目录: %s
- 进程名称: %s
- 失败次数: %d/%d
- 最后错误: %s

请检查服务配置和系统状态。`,
		service.Name,
		service.Name,
		service.Executable,
		service.WorkDir,
		service.ProcessName,
		status.FailureCount,
		service.MaxFailures,
		status.LastError)

	if err := SendEmail(&config.Email, subject, body); err != nil {
		fmt.Printf("发送服务失败邮件失败: %v\n", err)
	} else {
		fmt.Printf("已发送服务失败邮件: %s\n", service.Name)
	}
}

// MonitorService 监控单个服务
func MonitorService(service *ServiceConfig, emailConfig *EmailConfig, stopChan <-chan struct{}) {
	// 解析检查间隔
	checkInterval, err := ParseDuration(service.CheckInterval)
	if err != nil {
		fmt.Printf("服务 %s 的检查间隔解析失败: %v\n", service.Name, err)
		return
	}

	ticker := time.NewTicker(checkInterval)
	defer ticker.Stop()

	fmt.Printf("开始监控服务: %s (进程: %s, 检查间隔: %s)\n",
		service.Name, service.ProcessName, service.CheckInterval)

	for {
		select {
		case <-ticker.C:
			// 重新加载配置以支持动态更新
			config, err := LoadConfig("config.yaml")
			if err != nil {
				fmt.Printf("重新加载配置文件失败: %v\n", err)
				continue
			}

			// 查找当前服务的最新配置
			var currentService *ServiceConfig
			for _, s := range config.Services {
				if s.Name == service.Name {
					currentService = &s
					break
				}
			}

			if currentService == nil {
				fmt.Printf("服务 %s 的配置已从配置文件中移除\n", service.Name)
				serviceStatusesMutex.Lock()
				delete(serviceStatuses, service.Name)
				serviceStatusesMutex.Unlock()
				return
			}

			// 检查服务是否被禁用
			if !currentService.Enabled {
				fmt.Printf("服务 %s 已被禁用，跳过检查\n", service.Name)
				continue
			}

			// 更新检查间隔
			if currentService.CheckInterval != service.CheckInterval {
				newInterval, err := ParseDuration(currentService.CheckInterval)
				if err != nil {
					fmt.Printf("服务 %s 的新检查间隔解析失败: %v\n", service.Name, err)
					continue
				}
				fmt.Printf("服务 %s 的检查间隔已更新: %s -> %s\n",
					service.Name, service.CheckInterval, currentService.CheckInterval)
				service.CheckInterval = currentService.CheckInterval
				ticker.Reset(newInterval)
			}

			// 检查服务状态
			isRunning, err := CheckService(currentService)
			status := GetServiceStatus(service.Name)

			if err != nil {
				fmt.Printf("服务 %s 检查失败: %v\n", service.Name, err)
				UpdateServiceStatus(service.Name, false, err)

				// 检查是否达到最大失败次数
				if status.FailureCount >= currentService.MaxFailures {
					fmt.Printf("服务 %s 失败次数已达到最大值 %d，发送邮件通知\n",
						service.Name, currentService.MaxFailures)
					sendServiceFailureEmail(config, currentService, status)
					// 重置失败计数，避免重复发送邮件
					status.FailureCount = 0
				}
			} else {
				UpdateServiceStatus(service.Name, isRunning, nil)
				if isRunning {
					fmt.Printf("服务 %s 运行正常\n", service.Name)
				}
			}

		case <-stopChan:
			fmt.Printf("停止监控服务: %s\n", service.Name)
			return
		}
	}
}
